#!/usr/bin/env python
# encoding: utf-8


"""
@file: conditions.py
@time: 2016/11/21 下午4:31
"""
# 通用条件
from mathsolver.functions.base.base import BaseFunction, new_latex
from mathsolver.functions.base.objects import (BaseSymbolValue, BaseBelong, BaseEqs, BaseSinEqs, BaseSinEq, BaseEq,
                                               BaseMultiple, BaseTriangleSymbolValue, BaseIneq, BasePoly, BaseFunc,
                                               BaseSinFunc, BaseIneqs, BaseNumber, BasePoint)
from mathsolver.functions.base.geometry import BaseGeoEq, BaseTriangle
from sympy import (expand_trig, sin, cos, tan, pi, trigsimp, sqrt, expand, sympify, Interval, Symbol, FiniteSet, solve,
                   simplify, S)
from sympy.abc import x
from mathsolver.functions.sanjiao import sanjiao_utils as su
from mathsolver.functions.sanjiao import sanjiaoxing_utils as sjx
from mathsolver.functions.budengshi import common_opers as co
from mathsolver.functions.budengshi.jiebudengshi import JieBuDengShi
from mathsolver.functions.budengshi.ineq_constants import INEQ_SEARCH_KEY
from mathsolver.functions.sanjiao.tuxiang import SanJiaoHanShuTuXiangBianHuan, XiangLinDuiChengZhouQiuCan
from mathsolver.functions.sanjiao.huajian import trig_simplify
from mathsolver.functions.sanjiao.sanjiao_objects import SanJiaoXing
from mathsolver.functions.sanjiao.sanjiao_constants import SanJiaoXingKey, SanJiaoHanShuKey
from mathsolver.functions.sanjiao.zhouqi import ZhouQi
from mathsolver.functions.sanjiao.zuizhi import SanJiaoHanShuZuiZhi
from mathsolver.functions.sanjiao.tuxiang import DuiChengZhongXin
from mathsolver.functions.sanjiao.sanjiaohanchuchonghe import SanJiaoHanShuChongHe
from mathsolver.functions.sanjiao.triangle_constant import (TARGET_TRIANGLE_EXPR_KEY, TRIANGLE_SHAPR_SEARCH_KEY,
                                                            TRIANGLE_INEQ_SEARCH_KEY, TRIANGLE_NAME_SEARCH_KEY,
                                                            ACTUE_TRIANGLE, OBTUSE_TRIANGLE)
from mathsolver.functions.sanjiao.triangle_objects import BaseSanJiaoXing, MiddlePointOnTheEdge
from operator import itemgetter


# 设α∈(0,\\frac{π}{2})
class BelongCondition(BaseFunction):
    def solver(self, *args):
        b = args[0]
        if isinstance(b, BaseBelong):
            symb = b.var
            intl = b.interval
            self.output.append(BaseSymbolValue({symb: intl}))
            return self
        else:
            raise Exception('Type Match Error')


# 已知α是第二象限角
class XiangXianCondition(BaseFunction):
    def solver(self, *args):
        variable = args[0].sympify()
        text = args[1]
        var_intl = None
        quad = 1
        if text.find('第一') >= 0:
            var_intl = BaseSymbolValue({variable: Interval(0, pi / 2)})
            quad = 1
        elif text.find('第二') >= 0:
            var_intl = BaseSymbolValue({variable: Interval(pi / 2, pi)})
            quad = 2
        elif text.find('第三') >= 0:
            var_intl = BaseSymbolValue({variable: Interval(pi, 3 * pi / 2)})
            quad = 3
        elif text.find('第四') >= 0:
            var_intl = BaseSymbolValue({variable: Interval(3 * pi / 2, 2 * pi)})
            quad = 4
        # self.output.append(var_intl)
        self.output.append(var_intl)
        self.output.append(BaseSymbolValue({sympify(str(variable) + '_quadrant'): quad}))
        return self


# [在△ABC中,若cosBsinC=sinA],则△ABC的形状一定是()
# [在△ABC中,已知a=8,b=10,c=6],判断△ABC的形状()
class SanJiaoXingXingZhuangCondition(BaseFunction):
    def solver(self, *args):
        arg0 = args[0]
        if isinstance(arg0, BaseEqs) or isinstance(arg0, BaseSinEqs):
            output_value = dict(map(lambda t: (t[0], t[1]), arg0.sympify()))
            output_value['type'] = 'eqs'
            self.output.append(BaseSymbolValue(output_value))
        elif isinstance(arg0, BaseSinEq):
            output_value = {}
            k, v = arg0.sympify()
            output_value[k] = v
            output_value['type'] = 'sineq'
            self.output.append(BaseSymbolValue(output_value))
        else:
            self.output.append(BaseSymbolValue({'other': arg0}))
        return self


# 锐角条件
class RuiJiaoCondition(BaseFunction):
    def solver(self, *args):
        variables = args[0].sympify()
        if isinstance(variables, Symbol):
            self.output.append(BaseSymbolValue({variables: Interval.open(0, pi / 2)}))
        elif co.iterable(variables):
            for v in variables:
                self.output.append(BaseSymbolValue({v: Interval.open(0, pi / 2)}))
        else:
            raise Exception('Match Type Error')
        return self


# 已知a,b,c分别是△ABC的三个内角A,B,C所对的边
# 已知锐角△ABC的内角A,B,C的对边分别为a,b,c
class SanJiaoXingBianCondition(BaseFunction):
    def solver(self, *args):
        triangle_points = args[0].name
        self.output.append(BaseSanJiaoXing(*triangle_points))
        text = args[-1]
        if text.find('钝角') >= 0:
            self.output.append(BaseSymbolValue({TRIANGLE_SHAPR_SEARCH_KEY: OBTUSE_TRIANGLE}))
        elif text.find('锐角') >= 0:
            self.output.append(BaseSymbolValue({TRIANGLE_SHAPR_SEARCH_KEY: ACTUE_TRIANGLE}))
        return self


ABC_LINES_SUBS = (('line(A, B)', 'AB'), ('line(A, C)', 'AC'), ('line(B, C)', 'BC'))


# 某点为三角形中某个边上的中点
# Input: paramer1:中点; paramer2:边
class SanJiaoXingBianDeZhongDianCondition(BaseFunction):
    def solver(self, *args):
        triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
        point = args[0].sympify()
        edge = ''.join(args[1].value)
        triangle_obj.update_ration(MiddlePointOnTheEdge(point, edge))  # 更新关系某点为某边的中点
        return self


# 三角形信息，根据已知条件输出三角形的所有信息
# 一般三角形的一些 条件都经过这些处理。
class SanJiaoXingCondition(BaseFunction):
    def solver(self, *args):
        line_subs = (
            ('line(AB)', 'c'), ('line(A, B)', 'AB'), ('line(AC)', 'b'),
            ('line(A, C)', 'AC'), ('line(B, C)', 'BC'), ('line(BC)', 'a'))
        angle_subs = (('Angle(A)', 'A'), ('Angle(B)', 'B'), ('Angle(C)', 'C'))
        arg = args[0]
        if isinstance(arg, BaseTriangle):
            # self.output.append(BaseSymbolValue({TRIANGLE_NAME_SEARCH_KEY: arg.name})) #  丢掉原来的
            triangle_points = arg.name
            self.output.append(BaseSanJiaoXing(*triangle_points))
        elif isinstance(arg, BaseEqs) or isinstance(arg, BaseSinEqs) or isinstance(arg, BaseMultiple):  # 如果是等式组
            eqs = arg.sympify()
            triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
            # two_angle_subs = (('A+B', 'pi - C'), ('A+C', 'pi - B'), ('B+C', 'pi- A'))
            for l_expr, r_expr in eqs:
                f = l_expr - r_expr
                f = f.subs(sjx.get_triangle_subs())
                f = sjx.subs_triangle_expr(f)
                self.output.append(BaseTriangleSymbolValue({f: '0'}))
                if triangle_obj:
                    f = f.subs(sjx.get_triangle_subs())
                    triangle_obj.update_condition([f, '0'])
        elif isinstance(arg, (BaseEq, BaseSinEq)):
            l_expr, r_expr = arg.sympify()
            if isinstance(l_expr, type(S)) or l_expr == sympify('S_ABC'):  # 面积
                self.output.append(
                    BaseTriangleSymbolValue({sympify('(a+b+c)*(a+b-c)*(a+c-b)*(b+c-a)'): (4 * r_expr) ** 2}))
            else:
                f = l_expr - r_expr
                f = f.subs(line_subs).subs(angle_subs)
                self.output.append(BaseTriangleSymbolValue({f: '0'}))
                f = f.subs(sjx.get_triangle_subs())
                triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
                if triangle_obj:
                    f = f.subs(ABC_LINES_SUBS)
                    f = f.subs(sjx.get_triangle_subs())
                    triangle_obj.update_condition([f, '0'])
        elif isinstance(arg, BaseGeoEq):
            l_expr, r_expr = map(sympify, arg.value)
            l_expr = l_expr.subs(sjx.get_triangle_subs())
            r_expr = r_expr.subs(sjx.get_triangle_subs())
            self.output.append(BaseTriangleSymbolValue({l_expr: r_expr}))
            f = l_expr - r_expr
            f = f.subs(sjx.get_triangle_subs())
            triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
            if triangle_obj:
                f = f.subs(ABC_LINES_SUBS)
                f = f.subs(sjx.get_triangle_subs())
                triangle_obj.update_condition([f, '0'])
        elif isinstance(arg, BaseIneq):
            _1, op, _2 = arg.sympify()
            if op == '!=':  # 不等式
                pass
            else:
                self.output.append(BaseSymbolValue({TRIANGLE_INEQ_SEARCH_KEY: ''.join(map(str, arg.sympify()))}))
                self.output.append(BaseSymbolValue({'type': 'ineq'}))
        elif isinstance(arg, BasePoly):
            v = arg.sympify()
            text = args[1]
            if text.find('面积') >= 0:
                # self.output.append(BaseSymbolValue({'(a+b+c)*(a+b-c)*(a+c-b)*(b+c-a)': (4 * v) ** 2}))
                self.output.append(BaseTriangleSymbolValue({'(a+b+c)*(a+b-c)*(a+c-b)*(b+c-a)': (4 * v) ** 2}))
            if text.find('钝角三角形') >= 0:
                self.output.append(BaseSymbolValue({TRIANGLE_SHAPR_SEARCH_KEY: 'obtuse_triangle'}))
            elif text.find('锐角三角形') >= 0:
                self.output.append(BaseSymbolValue({TRIANGLE_SHAPR_SEARCH_KEY: 'acute_triangle'}))
                # self.output.append()
        elif isinstance(arg, BaseGeoEq):
            l_expr, r_expr = map(sympify, arg.value)
            f = l_expr - r_expr
            # f = f.subs(line_subs).subs(angle_subs)
            f = f.subs(sjx.get_triangle_subs())
            # self.output.append(BaseSymbolValue({f: '0'}))
            self.output.append(BaseTriangleSymbolValue({f: '0'}))
        else:
            raise Exception('Type Match Error')
        return self


# 点D在BC边上
class DianZaiBianShangCondition(BaseFunction):
    def solver(self, *args):
        point = args[0].sympify()
        edge = ''.join(map(str, args[1].sympify().args[0]))
        from mathsolver.functions.sanjiao.triangle_objects import PointOnTheEdge
        triangle_obj = self.search(TRIANGLE_NAME_SEARCH_KEY)
        if triangle_obj:
            ration = PointOnTheEdge(point, edge)
            triangle_obj.update_ration(ration)
        return self


# 已知角θ的顶点与原点重合,始边与x轴的正半轴重合,终边在直线y=2x上,则cos2θ=()
# 输出tan(θ) = 2
class ZhongBianCondition(BaseFunction):
    def solver(self, *args):
        symb = args[0]
        line_eq = args[1]
        slope = co.line_slope(line_eq)
        self.output.append(BaseSinEq([tan(symb), slope]))
        return self


# 设函数f(x)=\\sqrt{3}sin\\frac{πx}{m},若存在f(x)的极值点x_{0}满足x_{0}^{2}+[f(x_{0})]^{2}<m^{2},则m的取值范围是()
class SanJiaoHanShuJiZhiDian(BaseFunction):
    def solver(self, *args):
        y_symbol, trig_f = args[0].sympify()
        extreme_point = args[1].sympify()
        sim_f = trig_simplify(trig_f)
        x_symbol = sympify('x')
        trig_mon, const = co.split_mons_const(sim_f)
        trig_coef = su.trig_coeff(trig_mon)
        extreme_value = abs(trig_coef)
        extreme_fx = sympify('f(x)').subs(x_symbol, extreme_point)
        single_trig_f = trig_mon / trig_coef
        single_trig_arg = single_trig_f.args[0]
        if sim_f != trig_f:
            self.steps.append(['由题意可得,%s=%s' % (new_latex(sympify('f(x)')), new_latex(sim_f)), ''])
            self.steps.append(['则%s=%s' % (new_latex(extreme_fx), '\\pm ' + new_latex(extreme_value)), ''])
        else:
            self.steps.append(['由题意可得,%s=%s' % (new_latex(extreme_fx), '\\pm ' + new_latex(extreme_value)), ''])
        k_symbol = sympify('k')
        extreme_trig_arg = single_trig_arg.subs(x_symbol, extreme_point)
        extreme_eq = BaseEq([extreme_trig_arg, k_symbol * pi + sympify('pi/2')])
        self.steps.append(['且' + extreme_eq.printing(), ', %s \\in z' % new_latex(k_symbol)])
        extreme_value = solve(extreme_trig_arg - k_symbol * pi - sympify('pi/2'), extreme_point)[0]
        op_extreme_value = extreme_value.subs(k_symbol, 0)
        ineq_expr = args[2].sympify()
        ineq_expr_list = co.to_ineq_expr_list(str(ineq_expr))
        l_expr, op, r_expr = ineq_expr_list
        l_expr = sympify(l_expr).subs(extreme_fx, trig_coef).subs(extreme_point, op_extreme_value)
        r_expr = sympify(r_expr).subs(extreme_fx, trig_coef).subs(extreme_point, op_extreme_value)
        ineq_f = l_expr - r_expr
        param_symb = list(ineq_f.free_symbols)[0]
        ineq = BaseIneq([l_expr, op, r_expr])
        self.steps.append(['所以', ineq.printing()])
        result = JieBuDengShi().solver(ineq).output[0]
        intl = result.sympify().values()[0]
        self.steps.append(['求得' + str(param_symb), '的区间为' + new_latex(intl)])
        self.output.append(result)
        return self


# 三角形对象
class SanJiaoXingDuiXiang(BaseFunction):
    def solver(self, *args):
        obj = SanJiaoXing()
        self.output.append(BaseSymbolValue({SanJiaoXingKey: obj}))
        return self


# 根据最小正周期 求出x的系数值
# Input paramer1:三角函数, paramer2: 最小正周期
# 设函数f(x)=sin(ωx+φ)+cos(ωx+φ)(ω>0,|φ|<\\frac{π}{2})的最小正周期为π,f(-x)=f(x),则()
# #031 若函数y=\\frac{1}{2}sin(ωx+π)(ω>0)的最小正周期为2π,则ω=().
class ZuiXiaoZhengZhouQi(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数最小正周期')
        arg0 = args[0]
        cond_cycle = args[1].sympify()
        if isinstance(arg0, BaseEq) or isinstance(arg0, BaseSinFunc):
            fx, expr = arg0.sympify()
        else:
            fx = 'f'
            expr = arg0.sympify()
        sim_f = trig_simplify(expr)
        self.steps.append(['由于%s=%s' % (new_latex(fx), new_latex(expr)), ''])
        cycle = ZhouQi(verbose=True).solver(expr).output[0].sympify()
        cycle_symb = list(cycle.free_symbols)[0]
        cycle_symb_values = co.isolve_eq2(BaseEq([cycle, cond_cycle]))
        self.steps.append(['根据题意得', BaseEq([cycle, cond_cycle]).printing()])
        if self.search(cycle_symb):
            cycle_symb_intl = self.search(cycle_symb)
            self.steps.append(['因为 ' + new_latex(cycle_symb), ' \\in ' + new_latex(cycle_symb_intl)])
            cycle_symb_values = filter(lambda _: _ in cycle_symb_intl, cycle_symb_values)
            self.steps.append(['所以 ' + new_latex(cycle_symb), '=' + new_latex(FiniteSet(*cycle_symb_values))])
        else:
            self.steps.append(['所以 ' + new_latex(cycle_symb), '=' + new_latex(FiniteSet(*cycle_symb_values))])
        self.output.append(BaseSymbolValue({cycle_symb: FiniteSet(*cycle_symb_values)}))
        if len(cycle_symb_values) == 1:
            cycle_symb_value = cycle_symb_values[0]
            sim_f = sim_f.subs(str(cycle_symb), cycle_symb_value)
            self.steps.append(['所以 y = ' + new_latex(expr), '=' + new_latex(sim_f)])
        return self


# 三角函数的偶性
# f(x) = f(-x)
# 或者说明是偶数函数 若函数f(x)=sin\\frac{x+φ}{3}(φ∈[0,2π])是偶函数
class SanJiaoHanShuJiOuXingQiuCan(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数奇偶性')
        # trig_f = self.search(SanJiaoHanShuKey)
        # if not trig_f:
        #     raise Exception('Type Match Error')
        y_symbol, trig_f = args[0].sympify()
        f_l, f_r = '', ''
        text = ''
        if isinstance(args[1], BaseEq):
            f_l, f_r = args[1].sympify()
        elif isinstance(args[1], str):
            text = args[1]
        k_symbol = sympify('k')
        trig_mon, _ = co.split_mons_const(trig_f)
        trig_f_arg = su.trig_arg(trig_mon)
        param_symbol = list(FiniteSet(*trig_f_arg.free_symbols) - FiniteSet(sympify('x')))[0]
        param_expr = trig_f_arg.subs(x, 0)
        trig_type = su.trig_type(trig_mon)
        if (str(f_l) == str(sympify('f(x)')) and str(f_r) == str(sympify('f(-x)'))) or text.find('偶函数') >= 0:  # 偶函数
            if trig_type == sin:
                param_value = solve(param_expr - k_symbol * pi - pi / 2, param_symbol)[0]
            elif trig_type == cos:
                param_value = solve(param_expr - k_symbol * pi, param_symbol)[0]
            else:
                raise Exception('Type Match Error')
        elif (str(f_l) == str(sympify('f(x)')) and str(f_r) == str(sympify('-f(-x)'))) or text.find('奇函数') >= 0:  # 奇函数
            if trig_type == sin:
                param_value = solve(param_expr - k_symbol * pi, param_symbol)[0]
            elif trig_type == cos:
                param_value = solve(param_expr - k_symbol * pi - pi / 2, param_symbol)[0]
            elif trig_type == tan:
                param_value = solve(param_expr - k_symbol * pi / 2, param_symbol)[0]
        param_intl = self.search(param_symbol)
        for k_value in range(0, 10):
            tmp_value = param_value.subs(k_symbol, k_value)
            tmp_value = simplify(sympify(tmp_value))
            if tmp_value in param_intl:
                param_value = tmp_value
                break
        self.steps.append(
            ['根据' + args[0].printing() + '; 且' + '%s \\in %s' % (new_latex(param_symbol), new_latex(param_intl)),
             '得出 %s=%s' % (new_latex(param_symbol), new_latex(param_value))])
        last_trig_f = trig_f.subs(param_symbol, param_value)
        self.output.append(BaseSymbolValue({SanJiaoHanShuKey: last_trig_f}))
        self.output.append(BaseSymbolValue({param_symbol: param_value}))
        return self


# 设当x=θ时,函数f(x)=sinx-2cosx取得最大值,则cosθ=().
# 当函数y=sinx-\\sqrt{3}cosx(0≤x<2π)取得最大值时,x=().
class SanJiaoHanShuZuiZhiCondition(BaseFunction):
    def solver(self, *args):
        if len(args) == 3:  # 设当x=θ时,函数f(x)=sinx-2cosx取得最大值【param1 BaseEq; param2 BaseSinFunc param3 op_text】
            arg0 = args[0]
            arg1 = args[1]
            x_symbol = sympify('x')
            if isinstance(arg0, BaseEq):
                l, r = arg0.sympify()
                f = l - r
                symbs = list(f.free_symbols)
                op_symb = list(FiniteSet(*symbs) - FiniteSet(x_symbol))[0]
            else:
                op_symb = arg0.sympify()
            if isinstance(arg1, BaseSinFunc):
                y_symbol, expr = arg1.sympify()
                fx_name = sympify(arg1.name)
            else:
                y_symbol, expr = arg1.sympify()
                fx_name = y_symbol
            op_text = args[2]
            op_obj = SanJiaoHanShuZuiZhi(verbose=True).solver(arg1, op_text)
            op_value = op_obj.output[0].sympify()
            # op_steps = op_obj.steps
            op_text_print = '最大值' if op_text.find('最大') >= 0 else '最小值'
            self.steps.append(['由题意可知' + new_latex(fx_name) + op_text_print, '为' + new_latex(op_value)])
            new_trig_eq = BaseSinEq([expr.subs(x_symbol, op_symb), op_value])
            self.steps.append(['即' + new_trig_eq.printing(), ''])
            self.output.append(new_trig_eq)
            return self
        elif len(args) == 2:  # 【当函数y=sinx-\\sqrt{3}cosx(0≤x<2π)取得最大值时】,x=().
            arg0 = args[0]
            op_text = args[1]
            y_symbol, expr = arg0.sympify()
            x_symbol = list(expr.free_symbols)[0]
            if self.search(INEQ_SEARCH_KEY):
                ineqs = co.to_base(self.search(INEQ_SEARCH_KEY), BaseIneqs)
                ineq_intl = list(JieBuDengShi().solver(ineqs).output[0].sympify().values())[0]
                op_obj = SanJiaoHanShuZuiZhi(verbose=True).solver(arg0, co.to_base_interval(ineq_intl), op_text)
                self.output.append(BaseSymbolValue({x_symbol: ineq_intl}))
            else:
                op_obj = SanJiaoHanShuZuiZhi(verbose=True).solver(arg0, op_text)
            op_value = op_obj.output[0].sympify()
            sim_expr = trig_simplify(expr)
            self.steps.append(['由题意可知 %s=%s' % (new_latex(y_symbol), new_latex(sim_expr)), ''])
            self.steps.extend(op_obj.steps)
            self.output.append(BaseSinEq([expr, op_value]))
            return self


# 【已知△ABC的三个内角A、B、C成等差数列】,AB=1,BC=4,则边BC上的中线AD的长为().
class SanJiaoDengChaShuLieCondition(BaseFunction):
    def solver(self, *args):
        variables = args[0].sympify()
        new_eq = BaseSinEq([2 * variables[1], variables[0] + variables[2]])
        self.steps.append(['由题意可知:', new_eq.printing()])
        self.output.append(BaseSymbolValue({2 * variables[1]: (variables[0] + variables[2])}))
        return self


# △ABC中,内角A,B,C的对边分别为a,b,c,【已知a,b,c成等比数列】,\\cos B = \\frac{3}{4}.
class SanJiaoDengBiShuLieCondition(BaseFunction):
    def solver(self, *args):
        variables = args[0].sympify()
        new_eq = BaseSinEq([variables[1] ** 2, variables[0] * variables[2]])
        self.steps.append(['由题意可知:', new_eq.printing()])
        self.output.append(BaseSymbolValue({variables[1] ** 2: (variables[0] * variables[2])}))
        return self


# 若函数f(x)=cos2x+asinx在区间(\\frac{π}{6},\\frac{π}{2})是减函数,则a的取值范围是().
class SanJiaoHanShuDanDiaoXing(BaseFunction):
    def solver(self, *args):
        y_symbol, trig_f = args[0].sympify()
        intl = args[1].interval
        text = args[2]
        expan_trig_f = expand_trig(trig_f)
        trig_mons = co.ichain(co.find_reg_expr('sin\\(.*?\\)', expan_trig_f),
                              co.find_reg_expr('cos\\(.*?\\)', expan_trig_f))
        quad_mon = None
        single_mon = None
        for trig_mon in trig_mons:
            tmp_quad_mon = sympify(trig_mon) ** 2
            if expan_trig_f.subs(tmp_quad_mon, 0) != expan_trig_f:
                quad_mon = tmp_quad_mon
            else:
                single_mon = sympify(trig_mon)
        if not quad_mon:  # 如果没有这一项，则不符合这一类型
            raise Exception('Type Match Error')
        f2 = expan_trig_f.subs(trigsimp(1 - single_mon ** 2), 1 - single_mon ** 2)
        x_symbol = sympify('x')
        t_symbol = sympify('t')
        f2_sub = f2.subs(single_mon, t_symbol)
        t_intl_left, left_open = single_mon.subs(x_symbol, intl.left), intl.left_open
        t_intl_right, right_open = single_mon.subs(x_symbol, intl.right), intl.right_open
        t_intl = Interval(t_intl_left, t_intl_right, left_open=left_open,
                          right_open=right_open) if t_intl_left < t_intl_right else Interval(t_intl_right,
                                                                                             t_intl_left,
                                                                                             left_open=right_open,
                                                                                             right_open=left_open)
        self.steps.append(['由%s=%s' % (new_latex(trig_f), new_latex(f2)), ''])
        self.steps.append(['令t=' + new_latex(single_mon), ''])
        self.steps.append(['则原函数化为y=' + new_latex(f2_sub), ''])
        print_text = '增函数' if text.find('增') >= 0 else '减函数'
        self.steps.append([r'\because t在' + new_latex(t_intl), '时f(x)为' + print_text])
        from mathsolver.functions.hanshu.dandiao_qiucan import QuJianDiJianQiuCan, QuJianDiZenQiuCan
        if print_text.find('增函数') >= 0:
            param_intl_solve = QuJianDiZenQiuCan().solver(BaseFunc({'var': t_symbol, 'expression': f2_sub, 'type': '', 'name': 'f'}), co.to_base_interval(t_intl))
        else:
            param_intl_solve = QuJianDiJianQiuCan().solver(BaseFunc({'var': t_symbol, 'expression': f2_sub, 'type': '', 'name': 'f'}), co.to_base_interval(t_intl))
        return param_intl_solve


# 将函数y=2sin(2x+\\frac{π}{6})的图象向右平移\\frac{pi}{4}个单位,所得图象对应的函数为()
class SanJiaoTuXiangYiDongCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数图像的变换')
        y_symbol, src_f = args[0].sympify()
        text = args[1]
        if text.find('向右') >= 0:
            direct = '向右'
        elif text.find('向左') >= 0:
            direct = '向左'
        elif text.find('向上') >= 0:
            direct = '向上'
        elif text.find('向下') >= 0:
            direct = '向下'
        else:
            raise Exception('It not specify a direction')
        unit = args[2]
        solve_r = SanJiaoHanShuTuXiangBianHuan(verbose=True).solver(args[0], direct, unit)
        self.steps.extend(solve_r.steps)
        f2 = solve_r.output[0].sympify()
        self.output.append(BaseSinFunc([y_symbol, f2]))
        return self


# 若将函数y=tan(ωx+\\frac{π}{4})(ω>0)的图象向右平移\\frac{π}{6}个单位长度后,与函数y=tan(ωx+\\frac{π}{6})的图象重合,则ω的最小值为()
# Input paramer1:函数1; paramer2:方向文本; paramer3:移动单位; paramer4:重合的函数
class SanJiaoTuXiangYiDongChongHeCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数图像的变换')
        y_symbol, src_f = args[0].sympify()
        text = args[1]
        if text.find('向右'):
            direct = '向右'
        elif text.find('向左'):
            direct = '向左'
        elif text.find('向上'):
            direct = '向上'
        elif text.find('向下'):
            direct = '向下'
        else:
            raise Exception('It not specify a direction')
        unit = args[2]
        solve_r = SanJiaoHanShuTuXiangBianHuan(verbose=True).solver(BaseSinFunc([y_symbol, src_f]), direct, unit)
        self.steps.extend(solve_r.steps)
        f2 = solve_r.output[0].sympify()
        target_y_symbol, target_f = args[3].sympify()
        solve_f = SanJiaoHanShuChongHe().solver(BaseSinFunc([y_symbol, f2]), BaseSinFunc([target_y_symbol, target_f]))
        self.steps.extend(solve_f.steps)
        x_symbol = sympify('x')
        param_symbol = list(FiniteSet(*sympify(f2).free_symbols) - FiniteSet(x_symbol))[0]
        # output_eq = solve_f.output[0]
        output_eqs = solve_f.output[0]
        try:
            param_symbol_values = list(map(itemgetter(1), map(itemgetter(1), co.isolve_eqs(output_eqs))))
        except Exception:
            param_symbol_values = list(map(itemgetter(1), map(itemgetter(0), co.isolve_eqs(output_eqs))))
        # param_symbol_values = co.isolve_eq2(output_eq, param_symbol)
        self.steps.append(['所以 ' + new_latex(param_symbol),
                           '=' + new_latex(FiniteSet(*param_symbol_values)) + '其中' + su.print_belong_z('k')])
        self.output.append(BaseSymbolValue({param_symbol: param_symbol_values}))
        return self


# Input1 paramer1:三角函数表达式; paramer3:方向文本; paramer3:周期单位系数
# 将函数y=2sin(2x+\\frac{π}{6})的图象向右平移\\frac{1}{4}个周期后,所得图象对应的函数为()
class SanJiaoTuxiangZhouQiYiDong(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数周期')
        self.label.add('三角函数图像的变换')
        y_symbol, trig_expr = args[0].sympify()
        cycle = ZhouQi(verbose=True).solver(trig_expr).output[0].sympify()
        self.steps.append(['函数' + args[0].printing(), '的周期为T=' + new_latex(cycle)])
        text = args[1]
        if text.find('向右') >= 0:
            text = '向右'
        elif text.find('向左') >= 0:
            text = '向左'
        elif text.find('向上') >= 0:
            text = '向上'
        elif text.find('向下') >= 0:
            text = '向下'
        else:
            raise Exception('It don\'t specify a direction')
        unit = args[2].sympify() * cycle
        self.steps.append(['由题意即为函数' + args[0].printing() + ' 的图像%s平移%s个单位', ""])
        target_f = SanJiaoHanShuTuXiangBianHuan(verbose=True).solver(trig_expr, text, unit).output[0].sympify()
        self.steps.append(['可得图像对应的函数为y=' + new_latex(target_f), ''])
        self.steps.append(['既有' + BaseEq(['y', target_f]).printing(), ''])
        self.output.append(BaseSinEq([y_symbol, target_f]))
        # self.output.append()
        return self


# 如果函数y=3cos(2x+φ)的图象关于点(\\frac{4π}{3},0)中心对称,那么|φ|的最小值为()
class SanJiaoHanShuZhongXingDuiCheng(BaseFunction):
    def solver(self, *args):
        y_symbol, trig_expr = args[0].sympify()
        trig_coef, trig_type, trig_arg, trig_const = su.simp_trig_info(trig_expr)
        trig_arg = sympify(trig_arg)
        x_symbol = sympify('x')
        param_symbol = list(FiniteSet(*trig_arg.free_symbols) - FiniteSet(x_symbol))[0]
        t_symbol = sympify('t')
        new_trig_expr = trig_coef * trig_type(t_symbol) + trig_const
        center_point = DuiChengZhongXin(verbose=True).solver(BaseSinEq([y_symbol, new_trig_expr])).output[0].sympify()
        self.steps.append([r'\because 函数' + args[0].printing(), '图像关于点' + args[1].printing() + '中心对称'])
        point_x, point_y = args[1].sympify()
        arg_sub = trig_arg.subs('x', point_x)
        param_value = expand(solve(arg_sub - center_point, param_symbol)[0])
        self.steps.append([r'\therefore ' + BaseEq([arg_sub, center_point]).printing(),
                           r'\therefore ' + BaseEq([param_symbol, param_value]).printing()])
        # k_symbol = list(param_value.free_symbols)[0]
        _k = sympify('k')
        self.output.append(BaseSymbolValue({param_symbol: param_value, _k: S.Integers}))
        return self


# ABC的三个内角为A、B、C,求当A为何值时,cosA+2cos\\frac{B+C}{2}取得最大值,并求出这个最大值.
class SanJiaoXingJiaoXiaoYuanCondition(BaseFunction):
    def solver(self, *args):
        trig_expr = args[0].sympify()
        angles_subs = (('A+B', 'pi-C'), ('A+C', 'pi-B'), ('B+C', 'pi-A'))
        last_expr = None
        for angle_sub in angles_subs:
            tmp_expr = trig_expr.subs(*angle_sub)
            if len(tmp_expr.free_symbols) == 1:
                last_expr = tmp_expr
        self.steps.append(['由' + BaseEq(['A+B+C', pi]).printing(), '得' + BaseEq([trig_expr, last_expr]).printing()])
        self.output.append(BaseSymbolValue({TARGET_TRIANGLE_EXPR_KEY: last_expr}))
        return self


# 已知ω>0,0<φ<π,直线x=\\frac{π}{4}和x=\\frac{5π}{4}是函数f(x)=sin(ωx+φ)图象的两条相邻的对称轴,则φ=()
class XiangLinDuiChengZhouCondition(BaseFunction):
    def solver(self, *args):
        solve_f = XiangLinDuiChengZhouQiuCan()
        solve_f.known = self.known
        return solve_f.solver(*args)


# 三角函数对称轴
class SanJiaoHanShuDuiChengZhouCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数对称轴求参')
        f_symbol, f_expr = args[0].sympify()
        from mathsolver.functions.sanjiao.tuxiang import SanJiaoDuiChengZhouQiuCan
        x_symbol, sym_axis = args[1].sympify()  # 对称轴
        _solver = SanJiaoDuiChengZhouQiuCan(verbose=True).solver(BaseEq([f_symbol, f_expr]), BaseEq([x_symbol, sym_axis]))
        _cond_eq = _solver.output[0]  # 得出的等式
        self.steps.append(['\because ' + args[1].printing(), '是函数' + args[0].printing() + '图像的对称轴'])
        self.steps.append(['\therefore ', _cond_eq.printing()])

        return self


# class DuiChengZhouCondition(BaseFunction):
#     def solver(self, *args):
#         y_symbol, trig_f = args[0].sympify()
#         _, symmetry_axis1 = args[1].sympify()
#         _, symmetry_axis2 = args[2].sympify()
#         # f_symmetry_axis = DuiChenZhou(verbose=True).solver(BaseEq([y_symbol, trig_f])).output[0]
#         x_symbol = sympify('x')
#         sim_trig_f = trig_simplify(trig_f)
#         _1, t_type, t_arg, _2 = su.simp_trig_info(sim_trig_f)
#         x_coef = sympify(t_arg).coeff(x_symbol)
#         x_coef_param_symb = list(x_coef.free_symbols)[0]
#         const_param = list(FiniteSet(*trig_f.free_symbols) - FiniteSet(x_symbol, x_coef_param_symb))[0]
#         if t_type in [sin, cos]:
#             cycle_value = 2 * pi / abs(x_coef)
#         elif t_type in [tan, cot]:
#             cycle_value = pi / abs(x_coef)
#         else:
#             raise Exception('illegality trig function')
#         self.steps.append(
#             ['因为直线' + args[1].printing() + '和' + args[0].printing(),
#              '是函数' + args[0].printing() + '两条相邻的对称轴'])
#         cond_cycle = 2 * abs(symmetry_axis1 - symmetry_axis2)
#         param_solve = co.isolve_eq(BaseEq([cycle_value, cond_cycle]), x_coef_param_symb)
#         x_coef_param_symb_values = list(param_solve[x_coef_param_symb])
#         if self.search(x_coef_param_symb):
#             tmp_intl = self.search(x_coef_param_symb)
#             x_coef_param_symb_values = filter(lambda _: _ in tmp_intl, x_coef_param_symb_values)
#         x_coef_param_value = x_coef_param_symb_values[0]
#         self.steps.append(
#             ['所以T=' + latex(cond_cycle), ',所以' + latex(x_coef_param_symb) + '=' + latex(x_coef_param_value)])
#         const_param_intl = self.search(const_param)
#         f2 = sim_trig_f.subs(x_coef_param_symb, x_coef_param_value)
#         max_f = f2.subs(x_symbol, symmetry_axis1)
#         min_f = f2.subs(x_symbol, symmetry_axis2)
#         self.steps.append(['并且' + latex(max_f) + '与' + latex(min_f) + '分别是最大值与最小值', ''])
#         self.steps.append(['因为 ' + latex(const_param) + ' \in ' + latex(const_param_intl), ''])
#         s_a = min(symmetry_axis1, symmetry_axis2)
#         # if t_type == sin:
#         #     pass
#         # elif t_type == cos:
#         #     pass
#         # elif t_type
#         const_param_value = co.isolve_eq(BaseEq())
#         return self

# 已知函数y=\\tan(2x+φ)的图象过点( \\frac{π }{12},0),则φ可以是( )
# 输出未知变量的值列表
class SanJiaoHanShuGuoDianCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('待定系数法求参-三角函数')
        y_symbol, f_expr = args[0].sympify()
        x_value, y_value = args[1].sympify()
        x_symbol = sympify('x')
        eq = [y_value, f_expr.subs(x_symbol, x_value)]
        trig_solve = su.solve_trig_eq(BaseEq(eq))
        self.output.append(BaseSymbolValue({x_symbol: trig_solve}))
        return self


# 两对称轴相等 【已知函数f(x) = 3\\sin (ω x - \\dfrac{{{π }}}{6})(ω > 0)和g(x) = 2\\cos (2x + β ) + 1的图象的对称轴完全相同】.
# 若x ∈[0,\\dfrac{{{π}} }{2}],则f(x)的取值范围是.
# Input paramer1: 函数1 ; paramer2: 函数2
class SanJiaoHanShuDuiChengZhouXiangDengCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('两三角函数对称轴相等')
        arg1, arg2 = args
        self.steps.append(['由题意可知:', ''])
        from mathsolver.functions.sanjiao.tuxiang import DuiChenZhou
        _solve1 = DuiChenZhou().solver(arg1)
        _solve2 = DuiChenZhou().solver(arg2)
        for label in _solve1.label:
            self.label.add(label)
        sa1 = _solve1.output[0].value[1]
        sa2 = _solve2.output[0].value[1]
        self.steps.append(['函数' + arg2.printing(), '对称轴为:' + BaseEq(['x', sa1]).printing()])
        self.steps.append(['函数' + arg2.printing(), '对称轴为:' + BaseEq(['x', sa2]).printing()])
        return self


# 函数y = 2\\sin ( {\\dfrac{{{{π }}x}}{6} - \\dfrac{{{π }}}{3}} )(0 ≤ x ≤ 9)的最大值与最小值之和为 ()
class SanJiaoHanShuZuiZhiZhiHe(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数最值')
        op_obj = SanJiaoHanShuZuiZhi(verbose=True)
        op_obj.known = self.known
        max_value = op_obj.solver(args[0], '最大值').output[0].sympify()
        self.steps.append(['由题意可知函数' + args[0].printing(), '最大值为:' + new_latex(max_value)])
        min_value = op_obj.solver(args[0], '最小值').output[0].sympify()
        self.steps.append(['最大值为:', new_latex(min_value)])
        last_value = max_value + min_value
        self.steps.append(['所以答案为:' + new_latex(last_value), ''])
        self.output.append(BaseNumber(last_value))
        return self


# 三角函数与其他图像两个相邻交点的距离求参数
# style Input: paramer1:三角函数  paramer2:其他函数 paramer3:距离 Ouput:参数关系
class SanJiaoHanShuJiaoDianJuLiCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('利用三角函数图像中的距离求参数')
        arg1, arg2, arg3 = args
        f1_symbol, f1_expr = arg1.sympify()
        f2_symbol, f2_expr = arg2.sympify()
        _d = arg3.sympify()
        _A1, t1_type, t1_arg, _b1 = su.simp_trig_info(f1_expr)
        _A2, t2_type, t2_arg, _b2 = su.simp_trig_info(f2_expr)
        x_symbol = sympify('x')
        _w = t1_arg.coeff(x_symbol)
        _h = t1_arg.subs(x_symbol, 0)
        y_symbol = sympify('y')
        if t1_type in [sin, cos] and f2_symbol == y_symbol and (f2_expr == _A1 + _b1 or f2_expr == -_A1 + _b1):
            eq = [2 * pi / _w, _d]
        elif t1_type in [sin, cos] and f2_symbol == y_symbol and f2_expr == _b1:
            eq = [2 * pi / _w, 2 * _d]
        elif t1_type == tan and f2_symbol == y_symbol:
            eq = [pi / _w, _d]
        elif (t1_type == sin and t2_type == cos or t1_type == cos and t2_type == sin) \
                and _A1 == _A2 and t1_arg == t2_arg and _b1 == _b2:
            eq = [(pi / _w) ** 2 + (sqrt(2) * _A1) ** 2, _d ** 2]
        else:
            raise Exception('Type Match Error')
        self.output.append(BaseEq(eq))
        return self


# 两三角函数f(x), g(x)  关于直线 y = a 对称 得出一个方程
# Input paramer2: f(x); paramer2:g(x); paramer3:直线方程
class LiangSanJiaoHanShuZhiXianDuiCheng(BaseFunction):
    def solver(self, *args):
        self.label.add('两个三角函数对称轴的判断')
        arg1, arg2, arg3 = args
        f1_symbol, f1_expr = arg1.sympify()
        f2_symbol, f2_expr = arg2.sympify()
        f3_symbol, f3_expr = arg3.sympify()
        _x = sympify('x')
        param_symb = list(f3_expr.free_symbols)[0]
        t1_coef, t1_type, t1_arg, t1_const = su.simp_trig_info(f1_expr)
        _w1 = t1_arg.coeff(_x)
        t2_coef, t2_type, t2_arg, t2_const = su.simp_trig_info(f2_expr)
        _w2 = t2_arg.coeff(_x)
        if abs(t1_coef) != abs(t2_coef) or abs(_w1) != abs(_w2) or t1_const != t2_const:
            self.steps.append(['由题意可知:', '函数' + arg1.printing() + '与函数' + arg2.printing() + '没有对称轴'])
        elif abs(t1_coef) == abs(t2_coef) and abs(_w1) == abs(_w2) and t1_const == t2_const:
            _eq = BaseEq([f1_expr, f2_expr])
            self.steps.append(['由题意可知:', _eq.printing()])
            param_values = su.solve_trig_eq(_eq, param_symb)
            self.steps.append(['求得 ' + new_latex(param_symb), '值为:' + new_latex(FiniteSet(*param_values))])
            self.output.append(BaseSymbolValue({param_symb: param_values}))
        return self


# 区间上正弦函数零点个数求参数范围
# Input paramer1:三角函数; paramer2:区间; paramer3:零点个数
class TriangleLingDianGeShuQiuCanFanWei(BaseFunction):
    def solver(self, *args):
        self.label.add('正弦函数区间上零点个数得不等式')
        arg1, arg2, arg3 = args
        f_symb, f_expr = arg1.sympify()
        x_intl = arg2.interval
        count = arg3.sympify()
        f_expr_simp = su.i_trig_simplify(f_expr)  # 化简
        if f_expr_simp != f_expr:
            self.steps.append(['由题意可知:' + arg1.printing(), '=' + new_latex(f_expr_simp)])
        t_coef, t_type, t_arg, t_const = su.simp_trig_info(f_expr_simp)
        ll = sympify(str(x_intl.left))
        r = sympify(str(x_intl.right))
        if not (not ll.is_real and not r.is_real):
            raise Exception('The Interval left and right must be parameter')
        opened = x_intl.left_open or x_intl.right_open
        if t_type == cos:
            t_coef, t_type, t_arg, t_const = su.cos_2_sin(f_expr_simp)
            self.steps.append(['函数:' + arg1.printing, '=' + new_latex(t_coef * t_type(t_arg) + t_const)])
        x0_values = su.solve_trig_eq(BaseEq([f_expr_simp, 0]))
        x0 = list(co.flatten(map(lambda _: su.expr_value_list(_, Interval(0, pi / 2, left_open=True)), x0_values)))[0]
        from mathsolver.functions.sanjiao.zhouqi import ZhouQi
        cycle = ZhouQi().solver(BaseEq(['y', f_expr_simp])).output[0].sympify()  # 周期
        ineq = None
        ineq_op = '<' if opened else '<='
        if count % 2 == 0:
            ineq = [ll, ineq_op, 2 * cycle + pi - 2 * x0]
        elif count % 2 == 1:
            ineq = [r - ll, ineq_op, 2 * cycle]
        self.output.append(BaseIneq(ineq))
        return self


# 三角函数对称中心
# Input paramer1:三角函数; paramer2: 对称中心
class SanJiaoHanShuDuiChengZhongXingCondition(BaseFunction):
    def solver(self, *args):
        self.label.add('系数含参型——已知对称中心求参')
        from mathsolver.functions.sanjiao.sanjiao_duichengxing import SanJiaoHanShuDuiChengXingQiuCan
        _solver = SanJiaoHanShuDuiChengXingQiuCan().solver(*args)
        self.steps.extend(_solver.steps)
        _eq = _solver.output[0]
        param = sympify(co.eqs_symbs([_eq.sympify()])[0])
        param_value = co.isolve_eq2(_eq)
        self.output.append(BaseSymbolValue({param: param_value}))
        self.steps.append(['求得', BaseEq([param, param_value]).printing()])
        return self


if __name__ == '__main__':
    pass
